// echo partial file, should not compile along

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;
using HarmonyLib;
using Utils;
namespace GongfaEffect;

public partial class GongfaEffect {
    public static class DaTaiYin {
        public static short DefKey_VirginityTrue = typeof(Config.CharacterFeature.DefKey).GetField("VirginityTrue",(BindingFlags)(-1))==null?Config.CharacterFeature.DefKey.VirginityTrue:(short)typeof(Config.CharacterFeature.DefKey).GetField("VirginityTrue",(BindingFlags)(-1)).GetValue(null);
        public static short DefKey_VirginityFalse = typeof(Config.CharacterFeature.DefKey).GetField("VirginityFalse",(BindingFlags)(-1))==null?Config.CharacterFeature.DefKey.VirginityFalse:(short)typeof(Config.CharacterFeature.DefKey).GetField("VirginityFalse",(BindingFlags)(-1)).GetValue(null);
        public static short DefKey_Pregnant = typeof(Config.CharacterFeature.DefKey).GetField("Pregnant",(BindingFlags)(-1))==null?Config.CharacterFeature.DefKey.Pregnant:(short)typeof(Config.CharacterFeature.DefKey).GetField("Pregnant",(BindingFlags)(-1)).GetValue(null);
        public const short Defkey_DaTaiYin=55; // 目前这个方法并没有被暴露在defkey之外，因此只能如此使用。
        // 当然，这里直接patch整个genderkeepyoung了，所以洗髓经也适用这个patch
        public static void Patch(RobustHarmonyInstance HarmonyInstance, string ModIdStr){
            Utils.GetOffset();
            HarmonyInstance.PatchAll(System.Reflection.MethodBase.GetCurrentMethod().ReflectedType);
        }

        // [HarmonyPostfix]
        // [HarmonyPatch(typeof(GameData.Domains.SpecialEffect.CombatSkill.Baihuagu.Neigong.JinZhenFaMaiGong), "OnHealedInjury")]
        // static void OnHealedInjury(GameData.Domains.SpecialEffect.CombatSkill.Baihuagu.Neigong.JinZhenFaMaiGong __instance, int charId, bool isAlly, sbyte healMarkCount) {
        //     GameData.Utilities.AdaptableLog.Info(__instance.CharacterId.ToString()+"拦截治疗伤口:"+charId+", ally="+isAlly+", count="+healMarkCount);
        // }

        public static Dictionary<int,CaiBuZhiShu> EffectDict=new Dictionary<int,CaiBuZhiShu>();
        public static CaiBuZhiShu GetOrDefault(int CharacterId){
            CaiBuZhiShu neigong;
            if(!EffectDict.TryGetValue(CharacterId, out neigong)){
                neigong=new CaiBuZhiShu(CharacterId);
                EffectDict[CharacterId]=neigong;
            }
            return neigong;
        }
        [HarmonyPostfix]
        [HarmonyPatch(typeof(GameData.Domains.SpecialEffect.CombatSkill.Common.Neigong.GenderKeepYoung), "OnEnable")]
        public static void OnEnable(GameData.Domains.SpecialEffect.CombatSkill.Common.Neigong.GenderKeepYoung __instance, bool ___IsDirect, sbyte ___RequireGender, GameData.Common.DataContext context){
            if(__instance.CharObj.GetGender() == ___RequireGender) {
                if(___IsDirect){
                    // GameData.DomainEvents.Events.RegisterHandler_MakeLove(GetOrDefault(__instance.CharacterId).doml);
                    // GameData.DomainEvents.Events.RegisterHandler_AdvanceMonthBegin(GetOrDefault(__instance.CharacterId).doamb);
                } else {
                    // GameData.Utilities.AdaptableLog.Info("char id:"+__instance.CharacterId+"注册采补函数");
                    GameData.DomainEvents.Events.RegisterHandler_MakeLove(GetOrDefault(__instance.CharacterId).oml);
                    GameData.DomainEvents.Events.RegisterHandler_CombatCharFallen(GetOrDefault(__instance.CharacterId).occf);
                    GameData.DomainEvents.Events.RegisterHandler_AdvanceMonthBegin(GetOrDefault(__instance.CharacterId).oamb);
                }
            }
        }
        [HarmonyPostfix]
        [HarmonyPatch(typeof(GameData.Domains.SpecialEffect.CombatSkill.Common.Neigong.GenderKeepYoung), "OnDisable")]
        public static void OnDisable(GameData.Domains.SpecialEffect.CombatSkill.Common.Neigong.GenderKeepYoung __instance, bool ___IsDirect, sbyte ___RequireGender, GameData.Common.DataContext context){
            if(__instance.CharObj.GetGender() == ___RequireGender) {
                if(___IsDirect){
                    // GameData.DomainEvents.Events.UnRegisterHandler_MakeLove(GetOrDefault(__instance.CharacterId).doml);
                    // GameData.DomainEvents.Events.UnRegisterHandler_AdvanceMonthBegin(GetOrDefault(__instance.CharacterId).doamb);
                } else {
                    // GameData.Utilities.AdaptableLog.Info("char id:"+__instance.CharacterId+"注册采补函数");
                    GameData.DomainEvents.Events.UnRegisterHandler_MakeLove(GetOrDefault(__instance.CharacterId).oml);
                    GameData.DomainEvents.Events.UnRegisterHandler_CombatCharFallen(GetOrDefault(__instance.CharacterId).occf);
                    GameData.DomainEvents.Events.UnRegisterHandler_AdvanceMonthBegin(GetOrDefault(__instance.CharacterId).oamb);
                    EffectDict.Remove(__instance.CharacterId);
                }
            }
        }
        public class CaiBuZhiShu {
            int CharacterId;
            public static int CaiBuLimit=int.MaxValue;
            public static int drain=100;
            public static int disorder=10;
            public static short DirEff_XuanYuJIuLao=1496;
            public static short DirEff_YinYangZhouTianFa=137;
            public CaiBuZhiShu(int CharacterId){
                this.CharacterId=CharacterId;
            }

            public void doamb(GameData.Common.DataContext context){
                try {
                    GameData.Domains.Character.Character character;
                    if(GameData.Domains.DomainManager.Character.TryGetElement_Objects(this.CharacterId, out character) && !character.GetFeatureIds().Contains(DefKey_VirginityTrue)){
                        var lifeRecordCollection = GameData.Domains.DomainManager.LifeRecord.GetLifeRecordCollection();
                        int currDate = GameData.Domains.DomainManager.World.GetCurrDate();
                        var location = character.GetLocation();
                        if(context.Random.Next(10)==0){
                            character.AddFeature(context, DefKey_VirginityTrue, true);
                            lifeRecordCollection.AddTribulationContinued(this.CharacterId, currDate, location);
                            if(character.GetId()==GameData.Domains.DomainManager.Taiwu.GetTaiwuCharId() && GameData.Domains.Taiwu.Profession.ProfessionSkillHandle.TaoistMonkSkill_HasSurvivedAllTribulation()){
                                character.SetCurrAge(16,context);
                            }
                        } else {
                            var month=GameData.Domains.DomainManager.World.GetCurrMonthInYear();
                            character.older(character.GetId()==GameData.Domains.DomainManager.Taiwu.GetTaiwuCharId() && GameData.Domains.Taiwu.Profession.ProfessionSkillHandle.TaoistMonkSkill_HasSurvivedAllTribulation()?12:120,month,context);
                            var avatar = character.GetAvatar();
                            if (avatar.UpdateGrowableElementsShowingAbilities(character)) {
                                character.SetAvatar(avatar, context);
                            }
                            lifeRecordCollection.AddTribulationCanceled(this.CharacterId, currDate, location);
                            GameData.Domains.World.Notification.MonthlyNotificationCollection monthlyNotificationCollection = GameData.Domains.DomainManager.World.GetMonthlyNotificationCollection();
                            if(this.CharacterId == GameData.Domains.DomainManager.Taiwu.GetTaiwuCharId()){
                                monthlyNotificationCollection.AddAboutToDie(this.CharacterId);
                            }
                        }
                    }
                } catch (Exception e) {
                    logger("理论上过月变老的代码没有问题，但这里的确差点红字了，错误信息："+e.Message);
                }
            }
//! 秘闻大概可以不加……
                //GameData.Domains.Information.Collection.SecretInformationCollection secretInformationCollection = GameData.Domains.DomainManager.Information.GetSecretInformationCollection();


            public void doml(GameData.Common.DataContext context, GameData.Domains.Character.Character character, GameData.Domains.Character.Character target, sbyte makeLoveState) {
                if (
                    makeLoveState != 3 &&
                    (character.GetId() == this.CharacterId || target.GetId() == this.CharacterId)
                ) {
                    var month=GameData.Domains.DomainManager.World.GetCurrMonthInYear();

                    var defender = ((character.GetId() == this.CharacterId) ? target : character);
                    var attacker = ((character.GetId() == this.CharacterId) ? character : target);

                    attacker.older(120,month,context);
                    defender.younger(12,month,context);

                    var lifeRecordCollection = GameData.Domains.DomainManager.LifeRecord.GetLifeRecordCollection();
                    int currDate = GameData.Domains.DomainManager.World.GetCurrDate();
                    var location = character.GetLocation();
                    lifeRecordCollection.AddTribulationCanceled(this.CharacterId, currDate, location);
                }
            }
            public void oml(GameData.Common.DataContext context, GameData.Domains.Character.Character character, GameData.Domains.Character.Character target, sbyte makeLoveState) {
                // GameData.Utilities.AdaptableLog.Info("触发OnMakeLove:"+character.GetId()+"主动与"+target.GetId()+"ML");
                if (
                    //makeLoveState != 3 &&
                    (character.GetId() == this.CharacterId || target.GetId() == this.CharacterId)
                ) {
                    GameData.Domains.Character.Character defender = ((character.GetId() == this.CharacterId) ? target : character);
                    GameData.Domains.Character.Character attacker = ((character.GetId() == this.CharacterId) ? character : target);
                    // GameData.Utilities.AdaptableLog.Info("attacker id:"+this.CharacterId+"采补"+defender.GetId());
                    int add=DecNeili(defender,context,Math.Min(drain,defender.GetPureCurrNeili()/5))/3;
                    if(add>0){
                        int received=AddNeili(attacker,context,add);
                    }
                    // attacker.AddFeature(context, DefKey_VirginityTrue, true); // 不必保留这层膜……不然没人正练了
                    var month=GameData.Domains.DomainManager.World.GetCurrMonthInYear();
                    attacker.younger(3,month,context);
                    defender.older(4,month,context);
                    if(character.beautify(context))character.SetAvatar(character.GetAvatar(), context);
                }
            }
            public void occf(GameData.Common.DataContext context, GameData.Domains.Combat.CombatCharacter combatChar){
                if(GameData.Domains.DomainManager.Combat.IsCharInCombat(CharacterId, checkCombatStatus: false) && combatChar.GetId() != this.CharacterId) try {
                    var enemyChar=combatChar.GetCharacter();
                    var clothKey=enemyChar.GetEquipment()[4];
                    if(clothKey.IsValid()){
                        enemyChar.ChangeEquipment(context, 4, -1, GameData.Domains.Item.ItemKey.Invalid);
                    }
                } catch (Exception e) {
                    logger("理论上Mod没有问题，但这里的确差点红字了，错误信息："+e.Message);
                }
            }
            // public static unfairTrue=new UnfairTrue();
            public void oamb(GameData.Common.DataContext context){
                // var rand=context.Random;
                // context.Random=unfairTrue;
                try {
                    if(GameData.Domains.DomainManager.Character.TryGetElement_Objects(this.CharacterId, out var character) && character.GetCreatingType()==1){
                        var currDate=GameData.Domains.DomainManager.World.GetCurrDate();
                        var location=character.GetLocation();
                        var block = GameData.Domains.DomainManager.Map.GetBlock(location);
                        if(block.CharacterSet!=null){
                            foreach(int charId in block.CharacterSet){
                                if(charId!=this.CharacterId && GameData.Domains.DomainManager.Character.TryGetElement_Objects(charId, out var victim)) {
                                    GameData.Domains.DomainManager.Character.HandleRapeAction(context,character,victim);
                                    // character.MakeLove(context,victim,character.GetGender()!=0);
                                    // lifeRecordCollection.AddRapeSucceed(character.GetId(), currDate, victim.GetId(), location);
                                }
                            }
                            // var mod = new GameData.Domains.Character.ParallelModifications.PeriAdvanceMonthFixedActionModification(character);
                            // mod.MakeLoveTargetList = new List<ValueTuple<GameData.Domains.Character.Character, GameData.Domains.Character.ParallelModifications.PeriAdvanceMonthFixedActionModification.MakeLoveState, bool>>();
                            // foreach(int charId in block.CharacterSet){
                            //     GameData.Domains.Character.Character victim;
                            //     if(GameData.Domains.DomainManager.Character.TryGetElement_Objects(charId, out victim)) {
                            //         mod.MakeLoveTargetList.Add((victim, GameData.Domains.Character.ParallelModifications.PeriAdvanceMonthFixedActionModification.MakeLoveState.Illegal,false));
                            //     }
                            // }
                            // if(mod.MakeLoveTargetList.Count > 0){
                            //     var recorder = context.ParallelModificationsRecorder;
                            //     recorder.RecordType(GameData.Common.ParallelModificationType.PeriAdvanceMonthExecuteFixedActions);
                            //     recorder.RecordParameterClass(mod);
                            //     if(mod.MakeLoveTargetList.Count > CaiBuLimit){
                            //         var month=GameData.Domains.DomainManager.World.GetCurrMonthInYear();
                            //         character.older(7*mod.MakeLoveTargetList.Count,month,context);
                            //         foreach(var vt in mod.MakeLoveTargetList){
                            //             vt.Item1.younger(7,month,context);
                            //         }
                            //     }
                            // }
                        }
                    }
                    // logger($"char {character.GetId()} have creating type {character.GetCreatingType()}");
                } catch (Exception e) {
                    logger("理论上过月春宵代码没有问题，但这里的确差点红字了，错误信息："+e.Message);
                // } finally {
                //     context.Random=rand;
                }
            }
            public static int AddNeili(GameData.Domains.Character.Character character, GameData.Common.DataContext context, int AddAmount){
                Dictionary<short, GameData.Domains.CombatSkill.CombatSkill> combatSkills = GameData.Domains.DomainManager.CombatSkill.GetCharCombatSkills(character.GetId());
                bool haveSkillNeili=true;
                int repeat=0;
                while(haveSkillNeili){
                    haveSkillNeili=false;
                    foreach (KeyValuePair<short, GameData.Domains.CombatSkill.CombatSkill> keyValuePair in combatSkills) {
                        short skillTemplateId=keyValuePair.Key;
                        GameData.Domains.CombatSkill.CombatSkill skill=keyValuePair.Value;
                        var curr=skill.GetTotalObtainableNeili()-skill.GetObtainedNeili();
                        if(curr>0){
                            // GameData.Utilities.AdaptableLog.Info("PeiRanJue.AddNeili-循环中,charid="+character.GetId()+", repeat="+repeat+", Amount="+DecAmount);
                            if(curr>=AddAmount-repeat){
                                skill.ObtainNeili(context,(short)(AddAmount-repeat));
                                repeat=AddAmount;
                                break;
                            } else {
                                skill.ObtainNeili(context,(short)(curr));
                                repeat+=curr;
                                haveSkillNeili=true;
                            }
                        }
                    }
                }
                return repeat;
            }
            // public static FieldInfo _currNeili=typeof(GameData.Domains.Character.Character).GetField("_currNeili",(BindingFlags(-1)));
            public static FieldInfo _originBaseNeiliAllocation=typeof(GameData.Domains.Combat.CombatCharacter).GetField("_originBaseNeiliAllocation",(BindingFlags)(-1));
            public static int DecNeili(GameData.Domains.Character.Character character, GameData.Common.DataContext context, int DecAmount){
                //var character=defender.GetCharacter();
                Dictionary<short, GameData.Domains.CombatSkill.CombatSkill> combatSkills = GameData.Domains.DomainManager.CombatSkill.GetCharCombatSkills(character.GetId());
                bool haveSkillNeili=true;
                int repeat=character.GetExtraNeili();
                if(repeat>=DecAmount){
                    repeat=DecAmount;
                    character.ChangeExtraNeili(context, -DecAmount);
                } else if (repeat>0){
                    character.ChangeExtraNeili(context, -repeat);
                    while(haveSkillNeili){
                        haveSkillNeili=false;
                        foreach (KeyValuePair<short, GameData.Domains.CombatSkill.CombatSkill> keyValuePair in combatSkills) {
                            short skillTemplateId=keyValuePair.Key;
                            GameData.Domains.CombatSkill.CombatSkill skill=keyValuePair.Value;
                            var curr=skill.GetObtainedNeili();
                            if(curr>0){
                                // GameData.Utilities.AdaptableLog.Info("PeiRanJue.AddNeili-循环中,charid="+character.GetId()+", repeat="+repeat+", Amount="+DecAmount);
                                if(curr>=DecAmount-repeat){
                                    skill.ObtainNeili(context,(short)(curr+repeat-DecAmount));
                                    repeat=DecAmount;
                                    break;
                                } else {
                                    skill.ObtainNeili(context,(short)(-curr));
                                    repeat+=curr;
                                    haveSkillNeili=true;
                                }
                            }
                        }
                    }
                }
                if(repeat>0){
                    int neili=character.GetCurrNeili()-repeat;
                    if(neili<0){
                        //var orig=character.GetBaseNeiliAllocation();
                        //var alloc=
                        DeAlloc(character, context, ref neili);
                    }
                    // GameData.Utilities.AdaptableLog.Info("character.SetCurrNeili,charid="+character.GetId()+", neili="+neili);
                    character.SetCurrNeili(neili, context);
                }
                return repeat;
            }
            public static readonly int[] dealloc_order={0,1,3,2};
            public unsafe static GameData.Domains.Character.NeiliAllocation DeAlloc(GameData.Domains.Character.Character character, GameData.Common.DataContext context, ref int neili){
                GameData.Domains.Character.NeiliAllocation alloc=character.GetBaseNeiliAllocation();
                foreach(var type in dealloc_order){
                    var curr=*(alloc.Items+type);
                    //GameData.Utilities.AdaptableLog.Info("DeAlloc,charid="+character.GetId()+", neili="+neili+", type="+type+", curr="+curr);
                    //while(neili>=0 && --curr>=0){ // 车祸现场
                    while(neili<0 && --curr>=0){
                        neili+=GameData.Domains.Character.CombatHelper.CalcNeiliCost(curr);
                    //    GameData.Utilities.AdaptableLog.Info("       charid="+character.GetId()+", neili="+neili+", type="+type+", curr="+curr);
                    }
                    *(alloc.Items+type)=Math.Max((short)0,curr);
                    //GameData.Utilities.AdaptableLog.Info("DeAllocEnd,charid="+character.GetId()+", neili="+neili+", type="+type+", curr="+curr);
                }
                character.SetBaseNeiliAllocation(alloc,context);
                return alloc;
            }
        }
    }
}
